package com.gt.lib.twitter;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Locale;

import oauth.signpost.OAuthProvider;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthProvider;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.User;
import twitter4j.auth.AccessToken;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.res.Configuration;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;

public class TwitterApp 
	implements OnDismissListener, OnAuthorizeSuccessListener {
	
	private final String TAG = "TwitterApp";
	private final String DEFAULT_REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token";
	private final String DEFAULT_ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token";
	private final String DEFAULT_AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize";
	final static String DEFAULT_CALLBACK_URL = "twitter://callback";
	
	private boolean mQuietMode;
	
	private Context mContext;
	private String mConsumerKey;
	private String mSecretKey;
	private String mCallbackUrl;
	
	private TwitterDialog mTwitterDialog;
	private Twitter mTwitter;
	private TwitterSession mTwitterSession;
	private CommonsHttpOAuthConsumer mConsumer;
	private AccessToken mAccessToken;
	private OAuthProvider mOAuthProvider;
	
	private AuthorizeTask mAuthorizeTask;
	private ObtainAccessTokenTask mObtainAccessTokenTask;
//	private TweetTask mTweetTask;
	private TweetThread mTweetThread;
	
	private TwitterListener mListener;
	
	private final Handler mTwitterHandler = new Handler();
	
	public TwitterApp(Context context, String consumerKey, String secretKey) {
		this(context, consumerKey, secretKey, DEFAULT_CALLBACK_URL);
	}
	
	private TwitterApp(Context context, String consumerKey, String secretKey, String callbackUrl) {
		mContext = context;
		mConsumerKey = consumerKey;
		mSecretKey = secretKey;
		mCallbackUrl = callbackUrl;
		configTwitter();
	}
	
	private void configTwitter() {
		mTwitterDialog = new TwitterDialog(mContext);
//		ConfigurationBuilder builder = new ConfigurationBuilder();
//		builder.setOAuthConsumerKey(mConsumerKey);
//		builder.setOAuthConsumerSecret(mSecretKey);
//		TwitterFactory factory = new TwitterFactory(builder.build());
		mTwitter = new TwitterFactory().getInstance();
		mTwitterSession = new TwitterSession(mContext);
		mConsumer = new CommonsHttpOAuthConsumer(mConsumerKey, mSecretKey);
		mAccessToken = mTwitterSession.getAccessToken();
		
		mTwitterDialog.setOnAuthorizeSuccessListener(this);
		mTwitterDialog.setOnDismissListener(this);
		mTwitterDialog.progressDialog.setOnCancelListener(new OnCancelListener() {
			
			@Override
			public void onCancel(DialogInterface dialog) {
				onDismiss(dialog);
				mTwitterDialog.dismiss();
			}
		});
//		mTwitterDialog.setCallbackUrl(mCallbackUrl);
		configAccessToken();
		
	}
	
	private void configAccessToken() {
		if(mAccessToken != null) {
			mTwitter.setOAuthConsumer(mConsumerKey, mSecretKey);
			mTwitter.setOAuthAccessToken(mAccessToken);
		}
	}
	
	public void resetAccessToken() {
		if(mAccessToken != null) {
			mTwitterSession.resetAccessToken();
			mAccessToken = null;
			configTwitter();
		}
	}
	
	public void setTwitterListener(TwitterListener l) {
		mListener = l;
	}
	
	public void setQuietMode(boolean quietMode) {
		mQuietMode = quietMode;
	}
	
	public boolean isQuietMode() {
		return mQuietMode;
	}
	
	public void setTimeout(int timeout) {
		if(mTwitterDialog != null) {
			mTwitterDialog.setTimeout(timeout);
		}
	}
	
	public void setOnTimeoutListener(OnTimeoutListener l) {
		if(mTwitterDialog != null) {
			mTwitterDialog.setOnTimeoutListener(l);
		}
	}
	
	public void setLocale(Locale l) {
		Configuration config = mContext.getResources().getConfiguration();
		config.locale = l;
		mContext.getResources().updateConfiguration(config, null);
	}
	
	private void log(String msg) {
		Log.d(TAG, "<-- " + msg + " -->");
	}
	
	private void toast(int msg, int time) {
		toast(mContext.getString(msg), time);
	}
	
	private void toast(String msg, int time) {
		if(!mQuietMode) {
			Toast.makeText(mContext, msg, time).show();
		}
	}
	
	public boolean hasAccessToken() {
		return (mAccessToken == null) ? false : true;
	}
	
	public String getUserName() {
		return mTwitterSession.getUserName();
	}
	
	public void tweet(final String message, final OnTweetListener tweetListener) {
		if(mTweetThread != null) {
//			mTweetThread.stop();
			mTweetThread.cancel();
			mTweetThread = null;
			mTwitterDialog.dismissProgressDialog();
		}
		mTwitterDialog.showProgressDialog();
		mTweetThread = new TweetThread(message, tweetListener);
		mTweetThread.start();
//		mTweetTask = new TweetTask(tweetListener);
//		mTweetTask.execute(message);
	}
	
	public void tweet(String message) {
		this.tweet(message, null);
	}
	
	public void setOAuthProvider(CommonsHttpOAuthProvider provider) {
		mOAuthProvider = provider;
	}
	
	public Twitter operations() {
		return mTwitter;
	}
	
	public void setTypeface(Typeface tf) {
		if(mTwitterDialog != null) {
			mTwitterDialog.setTypeface(tf);
		}
	}
	
	@Override
	public void onDismiss(DialogInterface dialog) {
		if(mAuthorizeTask != null) {
			mAuthorizeTask.stop();
			mAuthorizeTask.cancel(true);
		}
		if(mObtainAccessTokenTask != null) {
			mObtainAccessTokenTask.cancel(false);
		}
//		if(mTweetTask != null) {
//			mTweetTask.cancel(true);
//		}
	}
	
	@Override
	public void onAuthorizeSuccess(String authorizationUrl) {
		log("onAuthorizeSuccess");
		log("authorizationUrl: " + authorizationUrl);
		obtainAccessToken(authorizationUrl);
	}
	
	public synchronized void authorize() {
		if(hasAccessToken()) {
			return ;
		}
		mTwitterDialog.showProgressDialog();
		mAuthorizeTask = new AuthorizeTask();
		mAuthorizeTask.execute();
	}
	
	public synchronized void obtainAccessToken(String authorizationUrl) {
		if(hasAccessToken()) {
			return ;
		}
		mTwitterDialog.showProgressDialog();
		mObtainAccessTokenTask = new ObtainAccessTokenTask();
		mObtainAccessTokenTask.execute(getVerifier(authorizationUrl));
	}
	
	private String getVerifier(String authorizationUrl) {
		String verifier	 = "";
		
		try {
			authorizationUrl = authorizationUrl.replace(DEFAULT_CALLBACK_URL, "http://");
			log("Getting verifiter");
			log("authorizationUrl: " + authorizationUrl);
			URL url 		= new URL(authorizationUrl);
			String query 	= url.getQuery();
			String array[]	= query.split("&");
			for (String parameter : array) {
	             String v[] = parameter.split("=");
	             if (URLDecoder.decode(v[0]).equals(oauth.signpost.OAuth.OAUTH_VERIFIER)) {
	            	 verifier = URLDecoder.decode(v[1]);
	            	 break;
	             }
	        }
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		
		return verifier;
	}
	
	private final class AuthorizeTask extends AsyncTask<Void, String, String> {

		private Boolean isRunning = true;
		
		@Override
		protected String doInBackground(Void... params) {
			Log.d(TAG, "doInBackground >> AuthorizeTask");
			String authorizationUrl = null;
//			AccessToken accessToken = null;
//			RequestToken requestToken = null;
			
			try {
//				mOAuthProvider.retrieveRequestToken(mConsumerKey, mSecretKey);
				
//				mTwitter.setOAuthConsumer(mConsumerKey, mSecretKey);
				if(mOAuthProvider == null) {
					mOAuthProvider = new CommonsHttpOAuthProvider(
							DEFAULT_REQUEST_TOKEN_URL, 
							DEFAULT_ACCESS_TOKEN_URL, 
							DEFAULT_AUTHORIZE_URL);
				}
				synchronized (mOAuthProvider) {
					authorizationUrl = mOAuthProvider.retrieveRequestToken(mConsumer, mCallbackUrl) + "&force_login=true";
//					authorizationUrl = mOAuthProvider.retrieveRequestToken(mConsumer, OAuth.OUT_OF_BAND) + "&force_login=true";
				}
			} catch(Exception e) {
				e.printStackTrace();
				authorizationUrl = null;
				publishProgress(mContext.getString(R.string.authorize_fail));
				if(mListener != null && !mTwitterDialog.isTimeout() && !mTwitterDialog.isCancelTask()) {
					mListener.onAuthorizeFail();
				}
			}
//			publishProgress("AuthorizationUrl: " + authorizationUrl);
			if(isCancelled()) {
				authorizationUrl = null;
			}
			return authorizationUrl;
		}
		

		@Override
		protected void onProgressUpdate(String... messages) {
			log(messages[0]);
			toast(messages[0], Toast.LENGTH_LONG);
			super.onProgressUpdate(messages);
		}

		@Override
		protected void onPostExecute(String authorizationUrl) {
			mTwitterDialog.dismissProgressDialog();
			if(mTwitterDialog.isTimeout() || mTwitterDialog.isCancelTask()) {
				return ;
			}
			if(authorizationUrl != null && !authorizationUrl.trim().equals("")) {
				Log.d(TAG, "is Running " + isRunning);
				if(isRunning) {
					mTwitterDialog.showLoginPage(authorizationUrl);
				}
			}
			super.onPostExecute(authorizationUrl);
		}
		
		public void stop() {
			synchronized (isRunning) {
				isRunning = false;
			}
		}
	}
	
	private final class ObtainAccessTokenTask extends AsyncTask<String , Void, Boolean> {

		@Override
		protected Boolean doInBackground(String... params) {
			Log.d(TAG, "doInBackground >> ObtainAccessTokenTask");
			boolean successful = false;
			try {
				log("Obtaining access token");
				log("Verifier: " + params[0]);
				synchronized (mOAuthProvider) {
					mOAuthProvider.setOAuth10a(true);
					mOAuthProvider.retrieveAccessToken(mConsumer, params[0]);
				}
				if(isCancelled()) {
					return false;
				}
				mAccessToken = new AccessToken(mConsumer.getToken(), mConsumer.getTokenSecret());
				configAccessToken();
				User user = mTwitter.verifyCredentials();
				mTwitterSession.StoreAccessToken(mAccessToken, user.getName());
				successful = true;
			} catch(Exception e) {
				Log.e(TAG, "<-- Error getting access token -->");
				mTwitterSession.resetAccessToken();
				e.printStackTrace();
			}
			return successful;
		}

		@Override
		protected void onPostExecute(Boolean result) {
			mTwitterDialog.dismissProgressDialog();
			mTwitterDialog.dismiss();
			if(mTwitterDialog.isTimeout() || mTwitterDialog.isCancelTask()) {
				return ;
			}
			if(!result) {
				if(mListener != null) {
					mListener.onAuthorizeFail();
				}
				toast(R.string.error_to_get_access_token, Toast.LENGTH_LONG);
			}
			else {
				if(mListener != null) {
					mListener.onAuthorizeSuccess();
				}
				log("Obtain access token successful.");
			}
			super.onPostExecute(result);
		}
	}
	
	private final class TweetThread extends Thread {

		private boolean isRunning;
		private Status status;
		private String message;
		private OnTweetListener tweetListener;
		
		public TweetThread(String message, OnTweetListener tweetListener) {
			this.message = message;
			this.tweetListener = tweetListener;
			isRunning = true;
		}	
		
		public void cancel() {
			isRunning = false;
		}
		
		@Override
		public void run() {
			if(isRunning) {
				try {
					status = mTwitter.updateStatus(message);
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					if(isRunning) {
						mTwitterHandler.post(new Runnable() {
							
							@Override
							public void run() {
								mTwitterDialog.dismissProgressDialog();
								if(status == null || status.getId() <= 0) {
									if(tweetListener != null) {
										tweetListener.onTweetFail(status);
									}
									toast(R.string.tweet_fail, Toast.LENGTH_SHORT);
								}
								else {
									if(tweetListener != null) {
										tweetListener.onTweetSuccess(status);
										
									}
									toast(R.string.tweet_success, Toast.LENGTH_SHORT);
								}
							}
						});
					}
				}
			
			}
		}
		
	}
	
//	private final class TweetTask extends AsyncTask<String, Void, Status> {
//		
//		private OnTweetListener mTweetListener;
//		
//		public TweetTask(OnTweetListener tweetListener) {
//			mTweetListener = tweetListener;
//		}
//
//		@Override
//		protected void onPreExecute() {
//			mTwitterDialog.showProgressDialog();
//			super.onPreExecute();
//		}
//
//		@Override
//		protected twitter4j.Status doInBackground(String... params) {
//			Log.d(TAG, "doInBackground >> TweetTask");
//			twitter4j.Status status = null;
//			String message = params[0];
//			try {
//				status = mTwitter.updateStatus(message);
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//			return status;
//		}
//
//		@Override
//		protected void onPostExecute(twitter4j.Status result) {
//			mTwitterDialog.dismissProgressDialog();
//			if(mTwitterDialog.isTimeout() || mTwitterDialog.isCancelTask()) {
//				return;
//			}
//			if(result != null) {
//				log("Tweet result: " + result.getId());
//			}
//			else {
//				log("Tweet fail with an exception.");
//			}
//			if(result == null || result.getId() <= 0) {
//				if(mTweetListener != null) {
//					mTweetListener.onTweetFail(result);
//				}
//				toast(R.string.tweet_fail, Toast.LENGTH_SHORT);
//			}
//			else {
//				if(mTweetListener != null) {
//					mTweetListener.onTweetSuccess(result);
//					
//				}
//				toast(R.string.tweet_success, Toast.LENGTH_SHORT);
//			}
//			super.onPostExecute(result);
//		}
//	}
}
